package com.qgs.secsgem.mq.secsgem;


import com.qgs.secsgem.mq.exception.T3TimeoutException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Author: 蔡翔
 * @Date: 2019/11/6 14:11
 * @Version 1.0
 *
 * （重点）
 * AsyncFuture 这个类就是票据，  刚拿到这个票据是没有信息的，当done == true 的时候，这个票据 上就自动有信息了
 * 这个结果类设计的比较神奇
 */
public class AsyncFuture<MQMessage> implements Future<MQMessage> {

    private static final Logger logger = LoggerFactory.getLogger(AsyncFuture.class);

    private volatile boolean done = false;
    private MQMessage oldRequest;
    private MQMessage result;

    public AsyncFuture(MQMessage oldRequest) {
        this.oldRequest = oldRequest;
    }
    public AsyncFuture() {
    }

    public void done(MQMessage result){
        synchronized (this){
            System.out.println("done");

            this.result = result;
            this.done = true;
            //注意这里的notifyAll只能唤醒 本锁的所有 下的所有 wait(),这里的锁就是 AsyncFuture这个类
            notifyAll();
        }
    }


    @Override
    public MQMessage get(Long timeout) throws Exception {
        synchronized (this){
            //其实有 synchronize就相当于有一个阻塞队列，当有线程执行了wait 方法，就会把执行wait的这个线程给加入wait<Thread> 队列，
            //当有线程执行notify方法的时候，就会往这个队列中取出一个或者多个Thread,取出来以后就能执行后续代码了
            System.out.println("get");

            // 当线程执行wait()时，会把当前的锁释放，然后让出CPU，进入等待状态。 wait()会立刻释放synchronized（obj）中的obj锁，以便其他线程可以执行obj.notify()
            // * 当线程执行notify()/notifyAll()方法时，会唤醒一个处于等待状态该对象锁的线程，然后继续往下执行，直到执行完退出对象锁锁住的区域（synchronized修饰的代码块）后再释放锁
            this.wait(timeout);
            if(!done){
                logger.error("T3 timeout , request information: "+oldRequest.toString());
                throw new T3TimeoutException("T3 timeout , request information: "+oldRequest.toString());
            }

            //因为上面的代码是加锁的，所以这里的代码也是加锁的。
            return result;
        }

    }
}
